//
//  01BasicContent.swift
//  cnswift-demo
//
//  Created by YangWei on 2022/7/20.
//  Copyright © 2022 YangWei. All rights reserved.
//

import Foundation

/// 基础内容
class BasicContent: NSObject {
    
    class func run() {
        
        let basicContent = BasicContent()
        
        // 1.1
        basicContent.declareConstantsAndvariables()
        
        // 1.2
        basicContent.typeAnnotation()
        
        // 1.3
        basicContent.nameConstantsAndVariables()
        
        // 1.4
        basicContent.outputConstantsAndVariables()
        
        // 2
        basicContent.codeAnnotation()
        
        // 3
        basicContent.semicolon()
        
        // 4
        basicContent.integerIntroduction()
        
        // 6
        basicContent.typeSafetyAndTypeInference()
        
        // 7
        basicContent.numericLiterals()
        
        // 8.1
        basicContent.integerConversion()
        
        // 8.2
        basicContent.integerAndFloatingPointConversion()
        
        // 9
        basicContent.typeAliases()
        
        // 10
        basicContent.booleans()
        
        // 11
        basicContent.tuples()
        
        // 12.0
        basicContent.optionals()
        
        // 12.1
        basicContent.nilIntroduce()
        
        // 12.2
        basicContent.ifStatementsAndForcedUnwrapping()
        
        // 12.3
        basicContent.optionalBinding()
        
        // 12.4
        basicContent.implicitlyUnwrappedOptionals()
        
        // 13
        basicContent.errorHandling()
        
        // 14.1
//        basicContent.debuggingWithAssertions()
        
        // 14.2
//        basicContent.enforcingPreconditions()
    }
    
    /// 1.1  声明常量和变量
    func declareConstantsAndvariables() {
        
        print("--- 1.1 声明常量和变量 ------------- start")
        
        // 声明一个 常量
        let maximumNumberOfLoginAttempts = 10
        
        // 声明一个 变量
        var currentLoginAttempt = 0

        print(maximumNumberOfLoginAttempts, currentLoginAttempt)
        
        // 一行声明多个
        var x = 0.0, y = 0.0, z = 0.0
        print(x, y, z)
        
        print("--- 1.1 声明常量和变量 ------------- end\n")
    }
    
    /// 1.2 类型标注
    func typeAnnotation() {
//        print("--- 1.2 类型标注 ------------- start")
        
        // 使用类型标注
        var welcomeMessage: String
        welcomeMessage = "Hello"
        
        /**
         没有初始值的变量需要添加类型标注
         设置初始值的变量不需要添加，swift 会自动推断变量类型
         */
        
        // 一行同时进行多个变量的类型标注
        var red, green, blue: Double
        
//        print("--- 1.2 类型标注 ------------- end")
    }
    
    /// 1.3 命名常量和变量
    func nameConstantsAndVariables() {
        
        print("--- 1.3 命名常量和变量 ------------- start")
        
        /**
         可以使用任何字符，甚至 Unicode 字符
         */
        let π = 3.14159
        
        let 你好 = "你好世界"
        
        let 🐶️🐮️ = "dogcow"
        
        
        var friendlyWelcome = "Hello!"
        friendlyWelcome = "Bonjour!"
        // friendlyWelcome 现在是 "Bonjour!"
        
        print(friendlyWelcome)
        
        let languageName = "Swift"
        // this is a compile-time error - languageName cannot be changed
        // languageName = "Swift++"
        
        print("--- 1.3 命名常量和变量 ------------- end\n")
    }
    
    /// 1.4 输出常量和变量
    /// ‼️ 如何使用 print
    func outputConstantsAndVariables() {
        
        print("--- 1.4 输出常量和变量 ------------- start")
        
        // 输出常量和变量
        /**
         print(_:separator:terminator:)
         一个全局函数，把一个或者多个值输出到 Xcode的 “console”
         separator 和 terminator 形式参数有默认值，调用函数时可以忽略传参
         函数默认在行末尾添加换行符来结束输出。去掉换行符可以 print(someValue, terminator: "")
         */
        // 一般打印
        var friendlyWelcome = "Hello!"
        friendlyWelcome = "Bonjour!"
        // friendlyWelcome 现在是 "Bonjour!"
        print(friendlyWelcome)
        
        // 使用 \() 插值打印 变量或常量
        print("The current value of friendlyWelcome is \(friendlyWelcome)")
        
        print("--- 1.4 输出常量和变量 ------------- end\n")
    }
    
    /// 2 注释
    func codeAnnotation() {
        // 这是一个单行注释

        /* 这是一个
        多行注释 */

        /* （嵌套注释）这是第一个多行注释的开头
        /* 这是第二个嵌套在内的注释块 */
        这是第一个注释块的结尾*/
    }
    
    /// 3 分号
    func semicolon() {
        
        print("--- 3 分号 ------------- start")
        
        /**
         Swift 不需要写 ; 单行多条语句需要写
         */
        let cat = "🐱️"; print(cat)
        
        print("--- 3 分号 ------------- end\n")
    }
    
    /// 4 整数
    func integerIntroduction() {
        
        /**
         整数
         例：
         8 位无符号整数的类型是 UInt8
         32 位有符号整数的类型是 Int32 。
         整数类型是大写开头的命名
         
         整数的范围：
         通过 min 和 max 属性来访问每个整数类型的最小值和最大值
         */
        let minValue = UInt8.min // 最小值是 0, 值的类型是 UInt8
        let maxValue = UInt8.max // 最大值是 255, 值得类型是 UInt8
    }
    
    /// 6 类型安全和类型推断
    func typeSafetyAndTypeInference() {
        
        let meaningOfLife = 42
        // meaningOfLife is inferred to be of type Int
        
        let pi = 3.14159
        // pi is inferred to be of type Double
        
        let anotherPi = 3 + 0.14159
        // anotherPi is also inferred to be of type Double
        
    }
    
    /// 7 数值型字面量
    func numericLiterals() {
        
        // 整数十进制值是 17 的表示：
        let decimalInteger = 17
        let binaryInteger = 0b10001 // 二进制 17
        let octalInteger = 0o21 // 八进制 17
        let hexadecimalInteger = 0x11 // 十六进制 17
        
        // 浮点值都是十进制的 12.1875 ：
        let decimalDouble = 12.1875
        let exponentDouble = 1.21875e1
        let hexadecimalDouble = 0xC.3p0
        
        // 增强代码可读性，不影响数值：
        let paddedDouble = 000123.456
        let oneMillion = 1_000_000
        let justOverOneMillion = 1_000_000.000_000_1
        
    }
    
    /// 8.1 整数转换
    func integerConversion() {
        
        print("--- 8.1 整数转换 ------------- start")
        
//        let cannotBeNegative: UInt8 = -1
        // UInt8 不能存储负值
//        let tooBig: Int8 = Int8.max + 1
        // Int8 不能存储超过 Int8 最大值的数字
        
        // 类型不同的变量不能直接相加
        let twoThousand: UInt16 = 2_000
        let one: UInt8 = 1
        
        // UInt16 (one ) 创建一个新的 UInt16 类型并用 one 的值初始化
        let twoThousandAndOne = twoThousand + UInt16(one)
        
        print("2000 + 1 = \(twoThousandAndOne)")
        
        print("--- 8.1 整数转换 ------------- end\n")
    }
    
    /// 8.2 整数和浮点数转换
    func integerAndFloatingPointConversion() {
        
        print("--- 8.2 整数和浮点数转换 ------------- start")
        
        let three = 3
        let pointOneFourOneFiveNine = 0.14159
        // 整数转化为浮点数 Double(three)
        let pi = Double(three) + pointOneFourOneFiveNine
        // pi 等于 3.14159, 类型是 Double
        
        print("pi(Double) = \(pi)")
        
        let integerPi = Int(pi)
        // integerPi 等于 3, 类型是 Int
        print("pi(Integer) = \(integerPi)")
        
        print("--- 8.2 整数和浮点数转换 ------------- end\n")
    }
    
    /// 9 类型别名
    /// ‼️ 如何使用 typealias
    func typeAliases() {
        
        print("--- 9 类型别名 ------------- start")
        
        typealias AudioSample = UInt16
        var maxAmplitudeFound = AudioSample.min // AudioSample.min 等价于 UInt16.min
        // maxAmplitudeFound is now 0
        
        print("maxAmplitudeFound 等价于 UInt16.min : \(maxAmplitudeFound)")
        
        print("--- 9 类型别名 ------------- end\n")
    }
    
    /// 10 布尔值
    func booleans() {
        
        print("--- 10 布尔值 ------------- start")
        
        // Bool 值：true 和 false
        let orangesAreOrange = true
        let turnipsAreDelicious = false

        if turnipsAreDelicious {
            print("Mmm, tasty turnips!")
        } else {
            print("Eww, turnips are horrible.")
        }
        // prints "Eww, turnips are horrible."
        
        
        // 不能像 OC 那样，用非布尔值变量直接判断 true 或者 false
//        let i = 1
//        if i {
//            // this example will not compile, and will report an error
//        }
        
        print("--- 10 布尔值 ------------- end\n")
    }
    
    /// 11 元组
    func tuples() {
        
        print("--- 11 元组 ------------- start")
        
        // 元组内的值可以是任何类型，而且可以不必是同一类型
        let http404Error = (404, "Not Found")
        
        // 可以将一个元组的内容分解成单独的常量或变量使用
        let (statusCode, statusMessage) = http404Error
        print("The status code is \(statusCode)")
        // prints "The status code is 404"

        print("The status message is \(statusMessage)")
        // prints "The status message is Not Found"
        
        
        // 分解元组，不需要的数据可以用下滑线（ _ ）代替
        let (justTheStatusCode, _) = http404Error
        print("The status code is \(justTheStatusCode)")
        // prints "The status code is 404"
        
        
        // 从零开始的索引数字去访问元组中的单独元素
        print("The status code is \(http404Error.0)")
        // prints "The status code is 404"

        print("The status message is \(http404Error.1)")
        // prints "The status message is Not Found"
        
        
        // 在定义元组的时候给其中的单个元素命名，使用时通过名字来访问
        let http200Status = (statusCode: 200, description: "OK")

        print("The status code is \(http200Status.statusCode)")
        // prints "The status code is 200"
        print("The status message is \(http200Status.description)")
        // prints "The status message is OK"
        
        print("--- 11 元组 ------------- end\n")
    }
    
    /// 12.0 可选项
    func optionals(){
        
        print("--- 12.0 可选项 ------------- start")
        
        let possibleNumber = "123"
        let number = 456
        let convertedNumber = Int(possibleNumber) // convertedNumber 是一个 可选的 Int
                
        print(type(of:number))
        print(type(of:convertedNumber))
        
        print("--- 12.0 可选项 ------------- end\n")
    }
    
    /// 12.1 nil
    func nilIntroduce() {
        
        print("--- 12.1 nil ------------- start")
        
        // 可选性变量声明 和 赋默认值
        var serverResponseCode: Int? = 404
        // 设置可选项值为 nil
        serverResponseCode = nil
        
        print("serverResponseCode = \(serverResponseCode)")

        // 可选性没有指定默认值，默认值为 nil
        var surveyAnswer: String?
        print("surveyAnswer = \(surveyAnswer)")
        
        print("--- 12.1 nil ------------- end\n")
    }
    
    /// 12.2 If 语句以及强制展开
    func ifStatementsAndForcedUnwrapping() {
        
        print("--- 12.2 If 语句以及强制展开 ------------- start")
        
        let possibleNumber = "123"
        let convertedNumber = Int(possibleNumber) // convertedNumber 是一个 可选的 Int
        
        if convertedNumber != nil {
            print("convertedNumber contains some integer value.")
        }
        // prints "convertedNumber contains some integer value."

        // 可选值的强制展开：确定可选中包含值，后面加一个感叹号 （ ! ） 来获取值
        if convertedNumber != nil {
            print("convertedNumber has an integer value of \(convertedNumber!).")
        }
        // prints "convertedNumber has an integer value of 123."
        
        
        // 可选性没有指定默认值，默认值为 nil
        var surveyAnswer: String?
        print("surveyAnswer 可选项声明 + 不赋初始值:\n", surveyAnswer as Any)
                
        // 如果可选值没有值，强制展开会报错：
        // 不做 nil 检查直接强制展开
//        print("surveyAnswer has an value of \(surveyAnswer!).")
        
        print("--- 12.2 If 语句以及强制展开 ------------- end\n")
    }
    
    /// 12.3 可选项绑定
    func optionalBinding() {
        print("--- 12.3 可选项绑定 ------------- start")
        
        /* 判断可选项是否包含值：
        if let constantName = someOptional {
            statements
        }
        */
        
        let possibleNumber = "123"

        // 如果  Int(possibleNumber)  返回的可选 Int 包含一个值，将这个可选项中的值赋予一个叫做 actualNumber 的新常量。”
        if let actualNumber = Int(possibleNumber) {
            // 如果要操作 actualNumber，可以声明 actualNumber 为 var
            print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
        } else {
            print("\'\(possibleNumber)\' could not be converted to an integer")
        }
        // prints "'123' has an integer value of 123"
        
        
        // 以下两个 if 等价：
        if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
        // Prints "4 < 42 < 100"
         
        if let firstNumber = Int("4") {
            if let secondNumber = Int("42") {
                if firstNumber < secondNumber && secondNumber < 100 {
                    print("\(firstNumber) < \(secondNumber) < 100")
                }
            }
        }
        // Prints "4 < 42 < 100"
        
        
        print("--- 12.3 可选项绑定 ------------- end\n")
    }
    
    /// 12.4 隐式展开可选项
    func implicitlyUnwrappedOptionals() {
        print("--- 12.4 隐式展开可选项 ------------- start")
        
        let possibleString: String? = "An optional string."
        let forcedString: String = possibleString! // 需要展开
         
        let assumedString: String! = "An implicitly unwrapped optional string."
        let implicitString: String = assumedString // 不再需要展开
        
        // 检查隐式展开可选项是否为 nil
        if assumedString != nil {
            print(assumedString)
        }
        // prints "An implicitly unwrapped optional string."

        // 也可以使用隐式展开可选项通过可选项绑定在一行代码中检查和展开值
        if let definiteString = assumedString {
            print(definiteString)
        }
        // prints "An implicitly unwrapped optional string."
        
        print("--- 12.4 隐式展开可选项 ------------- end\n")
        
    }
    
    /// 13 错误处理
    func errorHandling() {
        
        func canThrowAnError() throws {
            // this function may or may not throw an error
        }
        
        // 调用这个函数的地方需要添加 try 处理，例如：
        do {
            try canThrowAnError()
            // no error was thrown
        } catch {
            // an error was thrown
        }
        
        // do 语句创建一个新的容器范围，可以让错误被传递到到不止一个的 catch 分句里，例如：
        func makeASandwich() throws {
            // ...
            // throw(NSError.init(domain: "domain", code: 10001))
        }
         
        func eatASandwich() {
            print("eat a sandwich")
        }
        
        func washDishes() {
            print("washDishes")
        }
        
        /* 可以进行多个catch
        do {
            try makeASandwich()
            eatASandwich()
        } catch Error.OutOfCleanDishes {
            washDishes()
        } catch Error.MissingIngredients(let ingredients) {
            buyGroceries(ingredients)
        }
         */
    }
    
    /// 14.1 使用断言进行调试
    /// ‼️  assert(_:_:)  使用
    func debuggingWithAssertions() {
        
        print("--- 14.1 使用断言进行调试 ------------- start")
        
        // 向 assert(_:_:) 函数传入一个结果为 true 或者 false 的表达式，以及一条会在结果为 false 的时候显式的信息：
        let age = -3
        assert(age >= 0, "A person's age cannot be less than zero")
        // this causes the assertion to trigger, because age is not >= 0

        // 断言信息可以去掉
        assert(age >= 0)
        // Assertion failed
        
        // 代码已经检查了条件，可以使用 assertionFailure(_:file:line:) 函数来标明断言失败，
        // 比如：
        if age > 10 {
            print("You can ride the roller-coaster or the ferris wheel.")
        } else if age > 0 {
            print("You can ride the ferris wheel.")
        } else {
            assertionFailure("A person's age can't be less than zero.")
        }
        
        print("--- 14.1 使用断言进行调试 ------------- end\n")
    }

    /// 14.2 强制先决条件
    func enforcingPreconditions(){
        
        print("--- 14.2 强制先决条件 ------------- start")
        
        let index = -1
        
        // In the implementation of a subscript...
         precondition(index > 0, "Index must be greater than zero.")
        
        switch index {
        case 0:
            print("is 0")
            break
        default:
//            fatalError("此处还没实现")
            preconditionFailure("this is preconditionFailure")
        }
        
        print("--- 14.2 强制先决条件 ------------- end\n")
        
    }
}
